package com.yohann.algorithm;

/**
 * <p>
 * 综合计算表达式运算
 * 中缀表达式
 * </p>
 *
 * @author Yohann
 * @since 2020/9/23
 */
public class CalculatorTest {
    public static void main(String[] args) {
        String expression = "10+20-30+1*40/20";
        ArrayStack2 numStack = new ArrayStack2(10);
        ArrayStack2 operatorStack = new ArrayStack2(10);

        int index = 0;
        int num1 = 0;
        int num2 = 0;
        int oper = 0;
        int result = 0;
        char ch = ' ';
        String keepNum = "";

        while (true) {
            ch = expression.substring(index, index + 1).charAt(0);
            //判断是否为运算符
            if (operatorStack.isChar(ch)) {
                if (!operatorStack.isEmpty()) {

                    //当前运算符优先级别比栈内低
                    if (operatorStack.priority(ch) <= operatorStack.priority(operatorStack.getTop())) {
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = operatorStack.pop();
                        result = numStack.calculate(num1, num2, oper);

                        numStack.push(result);
                        operatorStack.push(ch);
                    } else {
                        operatorStack.push(ch);
                    }
                } else {
                    operatorStack.push(ch);
                }
            }
            //数字直接进栈
            else {
                keepNum += ch;

                //获取字符不是最后一位
                if (index != expression.length() - 1) {
                    //后一位为操作符
                    if (numStack.isChar(expression.substring(index + 1, index + 2).charAt(0))) {
                        numStack.push(Integer.parseInt(keepNum));
                        keepNum = "";
                    }
                } else {
                    numStack.push(Integer.parseInt(keepNum));
                    keepNum = "";
                }
            }

            index++;
            if (index >= expression.length()) {
                break;
            }
        }

        while (true) {
            if (operatorStack.isEmpty()) {
                break;
            }
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = operatorStack.pop();
            result = numStack.calculate(num1, num2, oper);

            numStack.push(result);
        }
        System.out.println(result);
    }
}

class ArrayStack2 {
    private int maxSize;
    private int[] stack;
    private int top = -1;

    public ArrayStack2(int maxSize) {
        this.maxSize = maxSize;
        this.stack = new int[this.maxSize];
    }

    //栈满
    public boolean isFull() {
        return top == maxSize - 1;
    }

    //栈空
    public boolean isEmpty() {
        return top == -1;
    }

    //入栈
    public void push(int value) {
        if (isFull()) {
            System.out.println("栈已满！");
            return;
        }

        stack[++top] = value;
    }

    //出栈
    public int pop() {
        if (isEmpty()) {
            throw new RuntimeException("栈已空！");
        }

        return stack[top--];
    }

    //遍历
    public void dispaly() {
        if (isEmpty()) {
            System.out.println("栈已空！");
        }

        for (int i = top; i > -1; i--) {
            System.out.print(stack[i] + " ");
        }
        System.out.println();
    }

    //获取栈顶
    public int getTop() {
        return stack[top];
    }

    //判断运算符优先级别
    public int priority(int operator) {
        if (operator == '*' || operator == '/') {
            return 1;
        } else {
            return 0;
        }
    }

    //判断是否是运算符
    public boolean isChar(char value) {
        return value == '+' || value == '-' || value == '*' || value == '/';
    }

    public int calculate(int num1, int num2, int operator) {
        int result = 0;
        switch (operator) {
            case '+':
                result = num1 + num2;
                break;
            case '-':
                result = num2 - num1;
                break;
            case '*':
                result = num1 * num2;
                break;
            case '/':
                result = num2 / num1;
                break;
            default:
                break;
        }

        return result;
    }
}